home *** CD-ROM | disk | FTP | other *** search
- ;;; xb-mouse.el: Functions to give emacs a more "X-behaved" mouse
- ;;; Copyright (C) 1993 by Thomas Crook (tcrook@u.cc.utah.edu)
- ;;;
- ;;; This program is free software; you can redistribute it and/or modify
- ;;; it under the terms of the GNU General Public License as published by
- ;;; the Free Software Foundation; either version 2 of the License, or
- ;;; (at your option) any later version.
- ;;;
- ;;; This program is distributed in the hope that it will be useful,
- ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;;; GNU General Public License for more details.
-
-
- ;;; Last Update: Wed Sep 8 12:53:13 1993 by tcrook@odo
- ;;;
- ;;; Description: This package provides X inter-client copy and paste for
- ;;; Emacs 19.19. It works simalarly to Xterm, providing
- ;;; word selection on double clicks and line selection on
- ;;; triple clicks.
- ;;;
- ;;; Disclaimer: This was a very fast hack and almost certainly needs
- ;;; improvements. However, the original author, Thomas Crook,
- ;;; is giving up his computer engineering career to pursue
- ;;; a PhD in marketing. He will not be providing updates or
- ;;; bug fixes. If people find this useful, it is the
- ;;; author's hope that some kind soul would adopt these
- ;;; orphaned functions and provide support for them.
- ;;;
- ;;; Needed Pasting from other X clients is known to be slow from
- ;;; Improvement: some machines, including SGI and HP PA-RISC. This may
- ;;; be due to a bug in Emacs itself.
- ;;;
- ;;; Acknowledgements: mouse-set-point:
- ;;; Hacked version of Gnu original
- ;;; local-mouse-drag-region:
- ;;; Hacked version of Glenn Coombs' hack
- ;;; of the Gnu original.
- ;;; Better behaved kill and yank stuff:
- ;;; Glenn Coombs,
- ;;; Phillips Research Labs,
- ;;; Redhill,
- ;;; ENGLAND
- ;;; (glenn@prl.philips.co.uk)
-
-
- (setq interprogram-cut-function nil)
- (setq interprogram-paste-function nil)
-
- ;;; Uncomment this if you want insertions to occur at the mouse pointer
- (define-key global-map [mouse-2] 'local-insert-x-selection-at-pointer)
- ;;; Uncomment this if you want insertions to occur at the point
- ;(define-key global-map [mouse-2] 'local-insert-x-selection-at-point)
-
- (define-key global-map [down-mouse-1] 'local-mouse-drag-region)
- (define-key global-map [mouse-3] 'local-mouse-save-then-kill)
-
- (defun local-insert-x-selection-at-pointer (event)
- "Sets the point to the mouse position and inserts the X selection
- to that point"
- (interactive "e")
- (let* ((posn (event-start event)))
- (and (window-minibuffer-p (posn-window posn))
- (not (minibuffer-window-active-p (posn-window posn)))
- (error "Minibuffer window is not active"))
- (select-window (posn-window posn))
- (if (numberp (posn-point posn))
- (progn
- (goto-char (posn-point posn))
- (insert (x-selection))))))
-
- (defun local-insert-x-selection-at-point ()
- "Pastes the X selection to wherever the point is"
- (interactive)
- (insert (x-selection)))
-
- (defun double-click-word-select ()
- "Select the word containing the point"
- (interactive)
- (forward-word 1)
- (backward-char 1)
- (mark-word 1)
- (forward-word -1)
- (x-set-cut-buffer (buffer-substring (point) (mark)))
- (x-set-selection 'PRIMARY (buffer-substring (point) (mark))))
-
- (defun triple-click-line-select ()
- "Select the line containing the point"
- (interactive)
- (end-of-line)
- (push-mark)
- (beginning-of-line)
- (x-set-cut-buffer (buffer-substring (point) (mark)))
- (x-set-selection 'PRIMARY (buffer-substring (point) (mark))))
-
- ;; Modified version of the Gnu original
- (defun mouse-set-point (event)
- "Move point to the position clicked on with the mouse.
- This should be bound to a mouse click event type."
- (interactive "e")
- ;; Use event-end in case called from mouse-drag-region.
- ;; If EVENT is a click, event-end and event-start give same value.
- (let* ((posn (event-end event))
- (clicks (event-click-count event)))
- (and (window-minibuffer-p (posn-window posn))
- (not (minibuffer-window-active-p (posn-window posn)))
- (error "Minibuffer window is not active"))
- (select-window (posn-window posn))
- (if (and (= clicks 1)
- (numberp (posn-point posn)))
- (goto-char (posn-point posn)))))
-
-
- ;;; Coombs:
- ;;; This is taken straight out of mouse.el. I have just added
- ;;; two lines at the bottom to add the selected text to the cut
- ;;; buffer and the primary selection.
- ;;; Crook:
- ;;; Added code to detect double and triple clicks and call
- ;;; double and triple click selection functions.
- (defun local-mouse-drag-region (start-event)
- "Set the region to the text that the mouse is dragged over.
- Highlight the drag area as you move the mouse.
- This must be bound to a button-down mouse event.
- In Transient Mark mode, the highlighting remains once you
- release the mouse button. Otherwise, it does not."
- (interactive "e")
- (let* ((start-posn (event-start start-event))
- (start-point (posn-point start-posn))
- (start-window (posn-window start-posn))
- (start-frame (window-frame start-window))
- (bounds (window-edges start-window))
- (top (nth 1 bounds))
- (bottom (if (window-minibuffer-p start-window)
- (nth 3 bounds)
- ;; Don't count the mode line.
- (1- (nth 3 bounds))))
- (clicks (event-click-count start-event)))
- (if (= clicks 3)
- (triple-click-line-select)
- (if (= clicks 2)
- (double-click-word-select)
- (progn
- (mouse-set-point start-event)
- (move-overlay mouse-drag-overlay
- start-point start-point
- (window-buffer start-window))
- (deactivate-mark)
- (let (event end end-point)
- (track-mouse
- (while (progn
- (setq event (read-event))
- (or (mouse-movement-p event)
- (eq (car-safe event) 'switch-frame)))
-
- (if (eq (car-safe event) 'switch-frame)
- nil
- (setq end (event-end event)
- end-point (posn-point end))
-
- (cond
-
- ;; Ignore switch-frame events.
- ((eq (car-safe event) 'switch-frame))
-
- ;; Are we moving within the original window?
- ((and (eq (posn-window end) start-window)
- (integer-or-marker-p end-point))
- (goto-char end-point)
- (move-overlay mouse-drag-overlay
- start-point (point)))
-
- ;; Are we moving on a different window on the same frame?
- ((and (windowp (posn-window end))
- (eq (window-frame (posn-window end)) start-frame))
- (let ((mouse-row
- (+ (nth 1 (window-edges (posn-window end)))
- (cdr (posn-col-row end)))))
- (cond
- ((< mouse-row top)
- (mouse-scroll-subr
- (- mouse-row top) mouse-drag-overlay start-point))
- ((and (not (eobp))
- (>= mouse-row bottom))
- (mouse-scroll-subr (1+ (- mouse-row bottom))
- mouse-drag-overlay start-point)))))
-
- (t
- (let ((mouse-y (cdr (cdr (mouse-position))))
- (menu-bar-lines (or (cdr (assq 'menu-bar-lines
- (frame-parameters)))
- 0)))
-
- ;; Are we on the menu bar?
- (and (integerp mouse-y) (< mouse-y menu-bar-lines)
- (mouse-scroll-subr (- mouse-y menu-bar-lines)
- mouse-drag-overlay start-point))))))))
-
- (if (and (eq (get (event-basic-type event) 'event-kind) 'mouse-click)
- (eq (posn-window (event-end event)) start-window)
- (numberp (posn-point (event-end event))))
- (progn
- (mouse-set-point event)
- (if (= (point) start-point)
- (deactivate-mark)
- (set-mark start-point)
- (x-set-cut-buffer (buffer-substring (point) (mark)))
- (x-set-selection 'PRIMARY (buffer-substring (point) (mark))))))
- (delete-overlay mouse-drag-overlay)))))))
-
-
-
- ;;; Crook: This is a modification of the Gnu original.
- ;;; I just added x-set-cut-buffer and x-set-selection calls
- ;;; as in function local-mouse-drag-region above
- (defun local-mouse-save-then-kill (click)
- "Save text to point in kill ring; the second time, kill the text.
- If the text between point and the mouse is the same as what's
- at the front of the kill ring, this deletes the text.
- Otherwise, it adds the text to the kill ring, like \\[kill-ring-save],
- which prepares for a second click to delete the text."
- (interactive "e")
- (let ((click-posn (posn-point (event-start click)))
- ;; Don't let a subsequent kill command append to this one:
- ;; prevent setting this-command to kill-region.
- (this-command this-command))
- (if (and (eq last-command 'local-mouse-save-then-kill)
- mouse-save-then-kill-posn
- (eq (car mouse-save-then-kill-posn) (car kill-ring))
- (equal (cdr mouse-save-then-kill-posn) (list (point) click-posn)))
- ;; If this is the second time we've called
- ;; local-mouse-save-then-kill, delete the text from the buffer.
- (progn
- ;; Delete just one char, so in case buffer is being modified
- ;; for the first time, the undo list records that fact.
- (delete-region (point)
- (+ (point) (if (> (mark) (point)) 1 -1)))
- ;; Now delete the rest of the specified region,
- ;; but don't record it.
- (let ((buffer-undo-list t))
- (delete-region (point) (mark)))
- (if (not (eq buffer-undo-list t))
- (let ((tail buffer-undo-list))
- ;; Search back in buffer-undo-list for the string
- ;; that came from the first delete-region.
- (while (and tail (not (stringp (car (car tail)))))
- (setq tail (cdr tail)))
- ;; Replace it with an entry for the entire deleted text.
- (and tail
- (setcar tail (cons (car kill-ring) (point)))))))
- ;; Otherwise, save this region.
- (mouse-set-mark-fast click)
- (kill-ring-save (point) (mark t))
- (x-set-cut-buffer (buffer-substring (point) (mark)))
- (x-set-selection 'PRIMARY (buffer-substring (point) (mark)))
- (mouse-show-mark)
- (setq mouse-save-then-kill-posn
- (list (car kill-ring) (point) click-posn)))))
-
- (provide 'xb-mouse)
-